﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace DevelopersToolbox {
    public partial class LineGraphControl : UserControl {
        private int _yAxisOffsetFromLeft;
        private int _xAxisOffsetFromBottom;

        public LineGraphControl() {
            InitializeComponent();
            MaxY = 10.0;
            MinY = 0.0;
            MaxX = 10.0;
            MinX = 0.0;
            BorderStyle = BorderStyle.FixedSingle;
            BackColor = SystemColors.Window;
            AxisColor = SystemColors.WindowText;
            DataSets = new DataSet[0];
            // DataSets = new DataSet[] {
            //     new DataSet{
            //        Color = Color.Blue,
            //        DataPoints = new DataPoint[] {
            //            new DataPoint {X=0, Y=0},
            //            new DataPoint {X=2, Y=1},
            //            new DataPoint {X=4, Y=2},
            //            new DataPoint {X=6, Y=3},
            //            new DataPoint {X=8, Y=4},
            //            new DataPoint {X=10, Y=5}
            //        }
            //     }
            //};
        }

        [DefaultValue(10.0)]
        public double MaxY { get; set; }

        [DefaultValue(0.0)]
        public double MinY { get; set; }

        [DefaultValue(10.0)]
        public double MaxX { get; set; }

        [DefaultValue(0.0)]
        public double MinX { get; set; }

        public DataSet[] DataSets { get; set; }

        [DefaultValue(typeof(Color), "WindowText")]
        public Color AxisColor { get; set; }

        private void LineGraphControl_Paint(object sender, PaintEventArgs e) {
            using (Brush axisBrush = new SolidBrush(AxisColor))
            using (Pen axisPen = new Pen(AxisColor)) {
                e.Graphics.Clear(BackColor);

                string minXString = string.Format("{0:0.##}", MinX);
                string maxXString = string.Format("{0:0.##}", MaxX);
                string minYString = string.Format("{0:0.##}", MinY);
                string maxYString = string.Format("{0:0.##}", MaxY);

                SizeF minXDims = e.Graphics.MeasureString(minXString, Font);
                minXDims.Height += 3; minXDims.Width += 2;
                SizeF maxXDims = e.Graphics.MeasureString(maxXString, Font);
                maxXDims.Height += 3; maxXDims.Width += 2;
                SizeF minYDims = e.Graphics.MeasureString(minYString, Font);
                minYDims.Width += 2;
                SizeF maxYDims = e.Graphics.MeasureString(maxYString, Font);
                maxYDims.Width += 2;

                _yAxisOffsetFromLeft = (int)Math.Max(minYDims.Width, maxYDims.Width);
                _xAxisOffsetFromBottom = (int)Math.Max(minXDims.Height, maxXDims.Height);

                // draw axis
                e.Graphics.DrawLine(axisPen, _yAxisOffsetFromLeft, 0, _yAxisOffsetFromLeft, Height - _xAxisOffsetFromBottom);
                e.Graphics.DrawLine(axisPen, _yAxisOffsetFromLeft, Height - _xAxisOffsetFromBottom, Width, Height - _xAxisOffsetFromBottom);

                // draw Y-axis labels
                e.Graphics.DrawString(maxYString, Font, axisBrush, 1, 1);
                e.Graphics.DrawString(minYString, Font, axisBrush, 1, Height - _xAxisOffsetFromBottom - minYDims.Height);

                // draw X-axis labels
                e.Graphics.DrawString(minXString, Font, axisBrush, _yAxisOffsetFromLeft, Height - _xAxisOffsetFromBottom);
                e.Graphics.DrawString(maxXString, Font, axisBrush, Width - maxXDims.Width, Height - _xAxisOffsetFromBottom);

                if (DataSets != null) {
                    foreach (DataSet dataSet in DataSets) {
                        using (Pen linePen = new Pen(dataSet.Color)) {
                            for (int i = 0; i < dataSet.DataPoints.Length; i++) {
                                DataPoint dp = dataSet.DataPoints[i];
                                if (dp.X >= MinX && dp.X <= MaxX && dp.Y >= MinY && dp.Y <= MaxY) {
                                    Point dpXY = GetXY(dp);
                                    if (dpXY.X < 0 || dpXY.Y < 0 || dpXY.X > Width || dpXY.Y > Height) {
                                        continue;
                                    }
                                    e.Graphics.DrawEllipse(linePen, dpXY.X - 1, dpXY.Y - 1, 2, 2);
                                    if (i > 0) {
                                        DataPoint lastDataPoint = dataSet.DataPoints[i - 1];
                                        Point lastDataPointXY = GetXY(lastDataPoint);
                                        e.Graphics.DrawLine(linePen, lastDataPointXY, dpXY);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        private Point GetXY(DataPoint dp) {
            double percentX = (dp.X - MinX) / (MaxX - MinX);
            double percentY = (dp.Y - MinY) / (MaxY - MinY);
            int width = Width - _yAxisOffsetFromLeft;
            int height = Height - _xAxisOffsetFromBottom;
            int x = (int)(_yAxisOffsetFromLeft + (width * percentX));
            int y = (int)(Height - _xAxisOffsetFromBottom - (height * percentY));
            return new Point(x, y);
        }
    }
}
